/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* includes (local) ----------------------------------------------------------*/
#include "a_config.h"
#include "a_exc.h"
#include "a_it.h"
/* includes (standard library, system) ---------------------------------------*/
#include <stdint.h>
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <x_config.h>
#include <x_common.h>
#include <x_module.h>

#include <hal_timer.h>

#ifdef CONFIG_PROFILE
#include <k_profile.h>
#endif

/* defines -------------------------------------------------------------------*/

/* SysTick Control and Status Register (STK_CTRL) */
#define STK_CTRL  (*(volatile uint32_t *)0xe000e010)
/* SysTick Reload Value Register (STK_LOAD) */
#define STK_LOAD  (*(volatile uint32_t *)0xe000e014)
/* SysTick Current Value Register (STK_VAL) */
#define STK_VAL   (*(volatile uint32_t *)0xe000e018)
/* SysTick Calibration Value Register (STK_CALIB) */
#define STK_CALIB (*(volatile uint32_t *)0xe000e01c)

#define STK_CTRL_ENABLE    (1 << 0)
#define STK_CTRL_TICKINT   (1 << 1)
#define STK_CTRL_CLKSOURCE (1 << 2)
#define STK_CTRL_COUNTFLAG (1 << 16)

#define STK_LOAD_MAX_COUNT 0xffffff

/* typedefs ------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* variables (global) --------------------------------------------------------*/
/* variables (extern) --------------------------------------------------------*/
/* variables (local) ---------------------------------------------------------*/

static unsigned long __reload_count = 0;

/* inlines -------------------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/

static int systick_enable(hal_timer_t *this, unsigned long count)
{
    __reload_count = count;

    STK_LOAD = count;
    STK_VAL = 0;
    STK_CTRL = 7;

    return 0;
}

static int systick_disable(hal_timer_t *this)
{
    STK_CTRL = 0;

    return 0;
}

static unsigned long systick_counter(hal_timer_t *this)
{
    return __reload_count - (unsigned long)STK_VAL;
}

static unsigned long systick_period(hal_timer_t *this)
{
    return __reload_count;
}

static const hal_timer_methods_t systick_methods = {
    .enable = systick_enable,
    .disable = systick_disable,
    .postpone = NULL,
    .prepone = NULL,
    .counter = systick_counter,
    .period = systick_period,
};

static hal_timer_t systick_timer = {
    .freq = CONFIG_SYSTEM_CORE_CLOCK,
    .max_count = STK_LOAD_MAX_COUNT,
    .methods = &systick_methods,
};

/**
 * systick_init - systick timer initialization routine
 *
 * return: 0 on success, negative value on error
 */
static int systick_init(void)
{
    /* hal_timer_register must not fail */

    return hal_timer_register(&systick_timer, "systick");
}

MODULE_INIT(service, systick_init);

/**
 * systick_handler - SysTick handler, override the weak one
 *
 * refer to a_handlers.c
 *
 * return: NA
 */
void systick_handler(void)
{
#ifdef CONFIG_PROFILE
    profile_sys_enter();
#endif

    if (systick_timer.handler != NULL) {
        systick_timer.handler(systick_timer.arg);
    }

    if (systick_timer.mode == HAL_TIMER_MODE_ONE_SHOT) {
        STK_CTRL = 0;
    } else {
        (void)STK_CTRL; /* reading CSR clears event */
    }

#ifdef CONFIG_PROFILE
    profile_sys_exit();
#endif
}
